#ifndef _RTOS_KERNEL_H_  
#define _RTOS_KERNEL_H_  
	
	#include "config.h"	
	#include "os.h"

	/**
	 * \file kernel.h
	 * \brief A Skeleton Implementation of an RTOS
	 * \author Clecio Varjao and Leanne Ross
	 * \date October 2007
	 * 
	 * A Skeleton Implementation of a "Full-Served" RTOS Model
	 * This is an example of how to implement context-switching based on a 
	 * full-served model. That is, the RTOS is implemented by an independent
	 * "kernel" task, which has its own stack and calls the appropriate kernel 
	 * function on behalf of the user task.
	 *	 	 
	 * \remarks Based on code of Dr. Mantis Cheng (2006)
	 */


	/*===========
	  * RTOS Internal
	  *===========
	  */

	/**
	  * This internal kernel function is the context switching mechanism.
	  * It is done in a "funny" way in that it consists two halves: the top half
	  * is called "Exit_Kernel()", and the bottom half is called "Enter_Kernel()".
	  * When kernel calls this function, it starts the top half (i.e., exit). Right in
	  * the middle, "Cp" is activated; as a result, Cp is running and the kernel is
	  * suspended in the middle of this function. When Cp makes a system call,
	  * it enters the kernel via the Enter_Kernel() software interrupt into
	  * the middle of this function, where the kernel was suspended.
	  * After executing the bottom half, the context of Cp is saved and the context
	  * of the kernel is restore. Hence, when this function returns, kernel is active
	  * again, but Cp is not running any more. 
	  * (See file "switch.S" for details.)
	  */
	extern void Exit_Kernel();    /* this is the same as CSwitch() */


	/** 
	  * This external function could be implemented in two ways:
	  *  1) as an external function call, which is called by Kernel API call stubs;
	  *  2) as an inline macro which maps the call into a "software interrupt";
	  *       as for the AVR processor, we could use the external interrupt feature,
	  *       i.e., INT0 pin.
	  *  Note: Interrupts are assumed to be disabled upon calling Enter_Kernel().
	  *     This is the case if it is implemented by software interrupt. However,
	  *     as an external function call, it must be done explicitly. When Enter_Kernel()
	  *     returns, then interrupts will be re-enabled by Enter_Kernel().
	  */ 
	extern void Enter_Kernel();

	/**
	  * This is the set of kernel requests, i.e., a request code for each system call.
	  */
	typedef enum kernel_request_type 
	{
	   NONE = 0,
	   CREATE=1,
	   NEXT=2,
	   TERMINATE=3, 
	   TICKTACK=4,
	   WAITFORNEXT=5
	} KERNEL_REQUEST_TYPE;

	/**
	  *  This is the set of states that a task can be in at any given time.
	  */
	typedef enum task_states 
	{ 
	   DEAD = 0, 
	   READY=1, 
	   RUNNING=2,
	   WAITING=3
	} TASK_STATES;


	typedef struct TaskConstructor{
		unsigned char allocated;	//!< Indicate whether the object is being used or not
		void (*code)(void);			//!< Pointer to a funcion to be executed
		int arg;					//!< Argument that can be retrieved by Task_GetArg()
		unsigned char level;		//!< Level of the task
		unsigned char name;			//!< Name of the PERIODIC task
	} TASK_CONSTRUCTOR;
	
	/**
	  * Each task is represented by a task descriptor, which contains all
	  * relevant information about this task. For convenience, we also store
	  * the task's stack, i.e., its workspace, in here.
	  */
	typedef struct TaskDescriptor
	{
		unsigned char allocated;	//!< Indicate whether the object is being used or not
		unsigned char *sp;   		//!< stack pointer into the "workSpace" //
		unsigned char workSpace[WORKSPACE];	
		TASK_CONSTRUCTOR *info; 	//!< Constructor of a TASK DESCRIPTION
		TASK_STATES state;			//!< State of this task ( see TASK_STATES)
	} TASK_DESCRIPTOR;

	/*********************************************************
		This structure controls the execution of a task.
	 ********************************************************/
	typedef struct TaskExecuter{
		unsigned char allocated;	//!< Indicate whether the object is being used or not
		unsigned char name;			//!< Optional. Name of the PERIODIC task.
		unsigned char level;		//!< SYSTEM, PERIODIC, RR, or IDLE
		TASK_DESCRIPTOR	*task;		//!< Pointer to the corresponding TASK_DESCRIPTION
		struct TaskExecuter	*owner;	//!< Pointer to the interrupted PERIODIC task
		unsigned int ticks;			//!< The amount of ticks used
		unsigned int maxTicks;		//!< The maximum amount of ticks that this task can run
		KERNEL_REQUEST_TYPE request;	//!< kernel request (see KERNEL_REQUEST_TYPE)
		TASK_CONSTRUCTOR *requestInfo;	//!< pointer to a TASK_CONSTRUCTOR when request=CREATE
	} TASK_EXECUTER;
	
	//Variables

	volatile TASK_EXECUTER		*curTE;
	extern volatile unsigned char KernelActive;	

	void OS_Error(int errorCode);
	int main();
	inline void kernel_tick(void);
	void Enter_Kernel(void);
	void Exit_Kernel(void);

	TASK_DESCRIPTOR *Kernel_Create_Task(TASK_CONSTRUCTOR *c);
	TASK_EXECUTER *Kernel_Create_And_Schedule(TASK_CONSTRUCTOR *c);
	void Kernel_Create_Task_At(TASK_DESCRIPTOR *d, TASK_CONSTRUCTOR *c);

	inline void kernel_wait_task(TASK_EXECUTER *e);
	inline void kernel_signal_task(TASK_EXECUTER *e);

#endif /* _RTOS_KERNEL_H_ */
